#include "cc_timer.h"
#include "cc_fs.h"
#include "cc_log.h"
#include "cc_shell.h"

void cc_timer_init(cc_timer_t timer, cc_timer_cb fun, uint8_t type, uint32_t ms,
                   void* data)
{
  timer->timer =
      xTimerCreateStatic("timer_create", ms, type, (void*)data, fun, &timer->entity);
}

cc_timer_t cc_timer_create(cc_timer_cb fun, uint8_t type, uint32_t ms,
                           void* data)
{
  cc_timer_t tim = (cc_timer_t)cc_malloc(sizeof(cc_timer));
  if (tim == CC_NULL)
  {
    cc_log_e("tim no mem\r\n");
    return CC_NULL;
  }
  cc_timer_init(tim, fun, type, ms, data);
  return tim;
}

cc_timer_t cc_timer_init_and_start(cc_timer_t timer, cc_timer_cb fun,
                                   uint8_t type, uint32_t ms, void* data)
{
  cc_timer_init(timer, fun, type, ms, data);
  cc_timer_start(timer);
  return timer;
}

cc_timer_t cc_timer_create_and_start(cc_timer_cb fun, uint8_t type, uint32_t ms,
                                     void* data)
{
  cc_timer_t tim = cc_timer_create(fun, type, ms, data);
  if (tim == CC_NULL)
  {
    cc_log_e("tim no mem\r\n");
    return CC_NULL;
  }
  cc_timer_start(tim);
  return tim;
}

int cc_timer_reset(cc_timer_t tim)
{
  if (tim == CC_NULL)
  {
    cc_log_e("tim no mem\r\n");
    return CC_ENOMEM;
  }
  if (cc_is_in_isr())
  {
    BaseType_t xHigherPriorityTaskWoken;
    int status = xTimerResetFromISR(&tim->timer, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    return status;
  }
  return xTimerReset(tim->timer, 0);
}

int cc_timer_start(cc_timer_t tim)
{
  if (tim == CC_NULL)
  {
    cc_log_e("tim no mem\r\n");
    return CC_ENOMEM;
  }
  if (cc_is_in_isr())
  {
    BaseType_t xHigherPriorityTaskWoken;
    int status = xTimerStartFromISR(&tim->timer, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    return status;
  }
  return xTimerStart(tim->timer, 0);
}

int cc_timer_set_mode(cc_timer_t tim, int mode)
{
  if (tim == CC_NULL)
  {
    cc_log_e("tim no mem\r\n");
    return CC_ENOMEM;
  }
  if (mode != cc_timer_one_shot && mode != cc_timer_auto_reload)
  {
    cc_log_e("param error\r\n");
    return CC_EINVAL;
  }
  vTimerSetReloadMode(tim->timer, mode);

  return CC_EOK;
}

int cc_timer_set_mode_start(cc_timer_t tim, int mode)
{
  if (CC_EOK == cc_timer_set_mode(tim, mode))
  {
    return cc_timer_start(tim);
  }
  else
  {
    return CC_EINVAL;
  }
}

int cc_timer_set_mode_stop(cc_timer_t tim, int mode)
{
  if (CC_EOK == cc_timer_set_mode(tim, mode))
  {
    return cc_timer_stop(tim);
  }
  else
  {
    return CC_EINVAL;
  }
}

int cc_timer_stop(cc_timer_t tim)
{
  if (tim == CC_NULL)
  {
    cc_log_e("tim no mem\r\n");
    return CC_ENOMEM;
  }
  if (cc_is_in_isr())
  {
    BaseType_t xHigherPriorityTaskWoken;
    int status = xTimerStopFromISR(&tim->timer, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    return status;
  }
  return xTimerStop(tim->timer, 0);
}

int cc_timer_change_time(cc_timer_t tim, uint32_t ms)
{
  if (tim == CC_NULL)
  {
    cc_log_e("tim no mem\r\n");
    return CC_ENOMEM;
  }
  if (cc_is_in_isr())
  {
    BaseType_t xHigherPriorityTaskWoken;
    int status = xTimerChangePeriodFromISR(&tim->timer, ms, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    return status;
  }
  return xTimerChangePeriod(tim->timer, ms, 0);
}

int cc_timer_change_time_and_start(cc_timer_t tim, uint32_t ms)
{
  if (tim == CC_NULL)
  {
    cc_log_e("tim no mem\r\n");
    return CC_ENOMEM;
  }
  cc_timer_change_time(tim, ms);
  return cc_timer_start(tim);
}

int cc_timer_change_time_and_stop(cc_timer_t tim, uint32_t ms)
{
  if (tim == CC_NULL)
  {
    cc_log_e("tim no mem\r\n");
    return CC_ENOMEM;
  }
  cc_timer_change_time(tim, ms);
  return cc_timer_stop(tim);
}

uint32_t cc_timer_get_systick()
{
  if (cc_is_in_isr())
  {
    return xTaskGetTickCountFromISR();
  }
  return xTaskGetTickCount();
}

void cc_timer_deinit(cc_timer_t tim)
{
  if (tim == CC_NULL)
  {
    return;
  }
  xTimerDelete(tim->timer, 0);
}
void cc_timer_destory(cc_timer_t tim)
{
  if (tim == CC_NULL)
  {
    return;
  }
  cc_timer_deinit(tim);
  cc_free(tim);
}
void heart_thread(void* data)
{
  if (!cc_fs_get_bool("heart_debug"))
  {
    cc_thread_suspend(cc_thread_self());
  }
  while (1)
  {
    cc_log("heart\r\n");
    cc_delay(10000);
  }
}
CC_THREAD_REGISTER(heart_thread, 2, 2048);

void heart_debug(char* param, int node)
{
  int operate = 0;
  cc_log_d("recv from node(%d):%s\r\n", node, param);
  if (cc_is_all_digits(param))
  {
    operate = atoi(param);
    if (operate < 0 || operate > 1)
    {
      cc_log_e("need 1 or 0\r\n");
      return;
    }
  }
  else
  {
    cc_log_e("need all digit param\r\n");
    return;
  }

  cc_tid heart_tid = cc_get_tid_by_cb(heart_thread);
  int state = cc_thread_get_state(heart_tid);
  cc_fs_set_bool("heart_debug", operate);
  if (operate == 0)
  {
    cc_msg_resp(node, "heart task is suspend\r\n", 0, (char*)CC_NULL);
    cc_thread_suspend(heart_tid);
  }
  if (operate == 1 && state == eSuspended)
  {
    cc_msg_resp(node, "heart task is running\r\n", 0, (char*)CC_NULL);
    cc_thread_resume(heart_tid);
  }
}
CC_COMMAND_SHELL(heart_debug, "open(1) close(0) heart task");

void reboot(char* param, int node)
{
  cc_msg_resp(node, "reboot!!!\r\n", 0, (char*)CC_NULL);
  cc_reboot();
}
CC_COMMAND_SHELL(reboot, "reboot mcu");